#include "operate.h"

//全局变量
static struct shm_param para;
struct pointMsg point; //存放点表信息
MQTTClient client;     //客户端
struct std_node *addr; //存放共享内存的地址

int *total_num_ptr = NULL;        //指向前四个字节的总数
struct std_node *data_ptr = NULL; //指向四个字节后的第一个结构体

//数据库所用
sqlite3 *db;
char *errmsg; //接收表错误信息

//线程id
pthread_t pd_sqlite;

//1解析点表
int main(int argc, char const *argv[])
{
    //log直接送往当前终端时，通过代码设置打印级别
    set_dbg_level(APP_DEBUG);

    int ret = -1; //共享内存映射是否成功

    //1 先映射共享内存，以备解析点表后存放使用
    ret = shm_init(&para, "shm_a", sizeof(struct std_node) * NUM + sizeof(int));
    if (ret < 0)
    {
        LOGE("共享内存初始化失败");
        return -1;
    }

    addr = shm_getaddr(&para);
    if (addr == NULL)
    {
        LOGE("共享内存映射失败");
        return -1;
    }
    //给总数地址和结构体的地址
    total_num_ptr = (int *)addr;
    data_ptr = (int *)addr + 1;
    *total_num_ptr = 0;

    //2 获取点表信息,将配置信息存入结构体，设备信息存入共享内存
    point = parsingPoint();
    if (point.port == -1)
    {
        LOGE("点表解析失败");
        shm_del(&para);
        return -1;
    }

    //3 连接到mqtt服务器,同时订阅，其recv可用做指令处理
    client = connectToMqtt(point);
    if (client == NULL)
    {
        LOGE("未能连接到MQTT服务器");
        shm_del(&para);
        return -1;
    }

    //4 初始化数据库
    if (sqlite3_open("data.db", &db) < 0)
    {
        fprintf(stderr, "sqlite3_open err:%s\n", sqlite3_errmsg(db));
        return -1;
    }
    LOGD("sqlite3_open ok\n");
    //创建用于存放数据信息的表
    if (sqlite3_exec(db, "create table data_table(time int,key int ,data char,primary key (time,key));", NULL, NULL, &errmsg) != 0)
    {
        fprintf(stderr, "sqlite3_open err:%s\n", errmsg);
    }
    LOGD("sqlite3 create table success\n");

    //5 创建数据存储线程
    if (pthread_create(&pd_sqlite, NULL, SaveToSqlite, NULL) != 0)
    {
        LOGE("pthread_create error\n");
    }

    //打印调试。。。
    for (int i = 0; i < *total_num_ptr; i++)
    {
        LOGD("%d:type:%d  dev_type:%d\n", data_ptr[i].key, data_ptr[i].type, data_ptr[i].dev_type);
    }
    //6 数据上报,只对应周期和变化上报，指令上报在此处只有延时
    sendCtr();

    //printf("hello world\n");
    MQTTClient_unsubscribe(client, TOPIC_DATA_DOWN);
    MQTTClient_unsubscribe(client, TOPIC_CTL_DOWN);
    MQTTClient_unsubscribe(client, TOPIC_MODE_DOWN);

    MQTTClient_disconnect(client, 10000);
    MQTTClient_destroy(&client);

    sqlite3_close(db);
    shm_del(&para);
    return 0;
}

void *SaveToSqlite(void *arg)
{
    int number = *total_num_ptr;
    struct std_node *temp = data_ptr;

    //sqlite command
    char sql[128] = "";

    //save val
    char buf[32] = "";

    //time
    char len[20] = {0};
    time_t timep;
    struct tm *p;

    while (1)
    {
        for (int i = 0; i < number; i++)
        {
            switch (temp[i].type)
            {
            case 1:
                sprintf(buf, "%d", temp[i].new_val.b_val);
                temp[i].old_val.b_val = temp[i].new_val.b_val;
                break;
            case 2:
                sprintf(buf, "%d", temp[i].new_val.i_val);

                temp[i].old_val.i_val = temp[i].new_val.i_val;
                break;
            case 3:
                sprintf(buf, "%.2f", temp[i].new_val.f_val);
                temp[i].old_val.f_val = temp[i].new_val.f_val;
                break;
            default:
                break;
            }
            //get now time
            time(&timep);
            p = localtime(&timep);
            snprintf(len, 20, "%d%d%d%d%d%d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, 8 + p->tm_hour, p->tm_min, p->tm_sec);
            LOGD("%s 存储\n", len);

            sprintf(sql, "insert into data_table values(\"%s\",\"%d\",\"%s\");", len, temp[i].key, buf);
            if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != 0)
            {
                fprintf(stderr, "insert err:%s\n", errmsg);
            }
        }
        sleep(60);
    }

    return NULL;
}
//
///select * from data_table where key=101 and time>2022112818100 and time <2022112818200;
